import json
import os
import random
from secrets import choice
from bisect import bisect_right
from django.db.models import Sum
from django.core.cache import cache
from warehouse.models import JuqiGood, GoodLevel, GoodLevelGameType
from .models import WuxianshangGame, WuxianshangGameGood, WuxianshangRaffleRecord
from juqiadmin.models import Finance
from juqiadmin.common.utlis import get_web_settings_statistical_exclude_user_uid_list

# from django_redis import get_redis_connection
import redis

# conn = get_redis_connection("default")
if os.environ.get("REDIS_LOCATION"):
    conn = redis.from_url(os.environ.get("REDIS_LOCATION"), decode_responses=True)
else:
    conn = redis.Redis(
        host=os.environ.get("REDIS_HOST")
        if os.environ.get("REDIS_HOST") is not None
        else "47.99.74.124",
        port=os.environ.get("REDIS_PORT")
        if os.environ.get("REDIS_PORT") is not None
        else 36379,
        password=os.environ.get("REDIS_PASSWORD")
        if os.environ.get("REDIS_PASSWORD") is not None
        else "juqi@123",
        decode_responses=True,
    )

# conn = cache

new_user_raffle_count = 100


def split_list_average_n(origin_list, n):
    for i in range(0, len(origin_list), n):
        yield origin_list[i : i + n]


class QuanjushangRaffle(object):
    def __init__(self):
        self.conn = conn

    def set_user_bit(self, user_id, value):
        redis_key = "wxs:user:raffle:state"
        self.conn.setbit(redis_key, user_id, value)

    def get_user_bit(self, user_id):
        redis_key = "wxs:user:raffle:state"
        result = self.conn.getbit(redis_key, user_id)
        return result

    def get_user_finance(self, user_id):
        redis_key = "wxs:user:raffle:hash"
        result = self.conn.hget(redis_key, user_id)
        if result is None:
            return {}, False

        return json.loads(str.replace(result, "'", '"', -1)), True

    def set_user_finance(self, user_id, res):
        redis_key = "wxs:user:raffle:hash"
        self.conn.hset(redis_key, user_id, str(res))

    def del_keys(self, game_uuid):
        for key in self.conn.keys(f"*{game_uuid}*"):
            self.conn.delete(key)

    # prize_init 初始化十万发赏品
    def init_prize(self, game_uuid):
        goods = []
        good_init_index = []  # 记录大奖的索引
        legend_good_uuid_list = []  # 传说赏品列表

        index = range(10000)
        wxs_goods = (
            WuxianshangGameGood.objects.filter(game_uuid=game_uuid, deleted=False)
            .filter(good_type=0)
            .order_by("-sort")
            .order_by("-id")
        )

        # 先拿到传说的level_uuid
        cs_good_level = GoodLevel.objects.filter(
            game_type=GoodLevelGameType.wuxianshang.value, title="传说款", deleted=False
        ).first()
        cs_good_uuids, cs_good_weight = [], 0
        max_good_weight, max_good_uuid = 0, ""
        other_goods = {}

        for i in wxs_goods[::-1]:
            if i.level_uuid == cs_good_level.uuid:
                for _ in range(int(i.good_weight * 10)):
                    cs_good_uuids.append(str(i.good_uuid))
                cs_good_weight += i.good_weight
                legend_good_uuid_list.append(str(i.good_uuid))
            else:
                if i.good_weight > max_good_weight:
                    max_good_weight = i.good_weight
                    max_good_uuid = str(i.good_uuid)
                other_goods[str(i.good_uuid)] = i.good_weight
        other_goods.pop(max_good_uuid, "")

        # 打乱 cs_good_uuids
        random.shuffle(cs_good_uuids)

        start_index, end_index = 0, int(cs_good_weight)
        for c in range(10):
            _good_list = [max_good_uuid] * 10000

            for k, v in other_goods.items():
                for _ in range(int(v)):
                    while True:
                        good_index = choice(index)
                        if _good_list[good_index] == max_good_uuid:
                            _good_list[good_index] = k
                            break
            for cs_good_uuid in cs_good_uuids[start_index:end_index]:
                while True:
                    good_index = choice(index)
                    if _good_list[good_index] == max_good_uuid:
                        _good_list[good_index] = cs_good_uuid
                        jq_good = JuqiGood.objects.filter(uuid=cs_good_uuid).first()
                        good_init_index.append(
                            {
                                "good_uuid": cs_good_uuid,
                                "good_name": jq_good.name,
                                "index": c * 10000 + good_index + 1,
                            }
                        )
                        break
            start_index, end_index = end_index, end_index + int(cs_good_weight)
            goods += _good_list

        good_init_index.sort(key=lambda k: (k.get("index", 0)))

        self.conn.set(
            f"wxs:{game_uuid}:maxTomin:good_uuids",
            str(legend_good_uuid_list[: len(legend_good_uuid_list) // 2]),
        )
        self.conn.set(
            f"wxs:{game_uuid}:{str(cs_good_level.uuid)}", str(legend_good_uuid_list)
        )
        self.conn.set(f"wxs:{game_uuid}:raffle:index", str(good_init_index))

        with self.conn.pipeline(transaction=False) as redis_three:
            new_goods = split_list_average_n(goods, 5000)
            for v in new_goods:
                for n in v:
                    redis_three.rpush(f"wxs:{game_uuid}:raffle", n)
                redis_three.execute()

    # 格式化抽过奖的无限赏redis.list
    def format_prize(self, game_uuid):
        # 先拿到传说的level_uuid
        cs_good_level = GoodLevel.objects.filter(
            game_type=GoodLevelGameType.wuxianshang.value, title="传说款", deleted=False
        ).first()

        legend_good_uuids = (
            WuxianshangGameGood.objects.filter(game_uuid=game_uuid)
            .filter(level_uuid=cs_good_level.uuid)
            .values_list("good_uuid")
        )
        legend_good_uuid_list = []
        for good_uuid in legend_good_uuids:
            legend_good_uuid_list.append(str(good_uuid[0]))

        wxs_rr_count = WuxianshangRaffleRecord.objects.filter(
            game_uuid=game_uuid
        ).count()

        wxs_rr_start_index = (wxs_rr_count // 100000) * 100000
        if wxs_rr_start_index != 0:
            wxs_rr_start_index += 1

        wxs_raffle_records = (
            WuxianshangRaffleRecord.objects.filter(game_uuid=game_uuid)
            .filter(good_uuid__in=legend_good_uuid_list)
            .filter(raffle_count__gte=wxs_rr_start_index)
        )

        r_r_dict = {}
        for wxs_r_r in wxs_raffle_records:
            good_uuid = str(wxs_r_r.good_uuid)
            if r_r_dict.get(good_uuid, 0) > 0:
                r_r_dict[good_uuid] += 1
            else:
                r_r_dict[good_uuid] = 1

        raffle_index = eval(self.conn.get(f"wxs:{game_uuid}:raffle:index"))

        for g_uuid, count in r_r_dict.items():
            self.conn.lrem(f"wxs:{game_uuid}:raffle", count, g_uuid)
            for _ in range(count):
                for index, item in enumerate(raffle_index):
                    if item.get("good_uuid") == g_uuid:
                        del raffle_index[index]
                        break

        self.conn.set(f"wxs:{game_uuid}:raffle:index", str(raffle_index))

    def get_game_good_index(self, wxs_game_uuid):
        return self.conn.get(f"wxs:{wxs_game_uuid}:raffle:index")

    # 从redis.list中pop一个赏品
    def get_good(self, wxs_game_uuid):
        return self.conn.lpop(f"wxs:{wxs_game_uuid}:raffle")

    # 获取无限池剩余奖品长度
    def get_good_len(self, wxs_game_uuid):
        return self.conn.llen(f"wxs:{wxs_game_uuid}:raffle")

    # 维护wxs出奖结果队列
    def raffle_record(self, wxs_game_uuid, good_uuid):
        self.conn.lpush(f"wxs:{wxs_game_uuid}:raffle_record", good_uuid)

    # 校验商品的等级是否需要进行大变小
    def check_good_level(self, game_uuid, good_uuid):
        good_uuids = self.conn.get(f"wxs:{game_uuid}:maxTomin:good_uuids")

        for v in good_uuids:
            if v == good_uuid:
                return True
        return False

    # 实现同级别商品大变小
    def good_max_to_mix(self, game_uuid, good_uuid, old_good):
        good = WuxianshangGameGood.objects.filter(
            game_uuid=game_uuid, good_uuid=good_uuid
        )
        good_uuids = eval(self.conn.get(f"wxs:{game_uuid}:maxTomin:good_uuids"))
        good_level_ = eval(self.conn.get(f"wxs:{game_uuid}:{good.level_uuid}"))

        for v in good_uuids:
            if v == good_uuid:
                if good_level_.index(good_uuid) > 3:
                    return good_uuid
                else:
                    choice_good_level_ = good_level_[4:]
                    while True:
                        new_good_ = choice(choice_good_level_)

                        result = self.conn.linsert(
                            game_uuid, "before", new_good_, old_good
                        )  # 在队列中的第一个新赏品前插入旧的赏品
                        if result != -1:
                            break

                        choice_good_level_.remove(new_good_)

                    self.conn.lrem(game_uuid, new_good_, 1)  # 删除队列中第一个新赏品

                    return new_good_

    def good_max_to_mix_v2(self, game_uuid, good_uuid):
        good_uuids = eval(self.conn.get(f"wxs:{game_uuid}:maxTomin:good_uuids"))

        good = WuxianshangGameGood.objects.filter(
            game_uuid=game_uuid, good_uuid=good_uuid
        ).first()

        goods = (
            WuxianshangGameGood.objects.filter(
                game_uuid=game_uuid, level_uuid=good.level_uuid
            )
            .exclude(good_uuid__in=good_uuids)
            .order_by("id")
        )

        return goods[-1].good_uuid

    def qjs_raffle(self, user_id, user_uuid, game_uuid, raffle_count):
        raffle_good = {}
        raffle_good_list = []

        # 主播用户抽奖
        if check_user_id_is_t(user_id):
            good_weight = get_wxs_game_goods(game_uuid, [], True)
            raffle_goods_dict, raffle_goods_list = random_raffle_goods(
                raffle_count, good_weight
            )
            return raffle_goods_dict, raffle_goods_list

        # 判断是否新用户
        current_raffle_count = WuxianshangRaffleRecord.objects.filter(
            user_uuid=user_uuid
        ).count()
        if current_raffle_count <= new_user_raffle_count:
            exclude_good_level = (
                GoodLevel.objects.filter(game_type=GoodLevelGameType.wuxianshang.value)
                .filter(title="传说款")
                .first()
            )
            good_weight = get_wxs_game_goods(
                game_uuid, [str(exclude_good_level.uuid)], False
            )
            raffle_goods_dict, raffle_goods_list = random_raffle_goods(
                raffle_count, good_weight
            )
            return raffle_goods_dict, raffle_goods_list

        # 查询用户在redis中的记录
        r_finance_res, r_f_state = self.get_user_finance(user_id)
        user_raffle_index = self.conn.get(f"wxs:user:raffle:{user_id}")
        if not r_f_state:
            res = Finance.objects.filter(user_uuid=user_uuid).aggregate(
                Sum("all_raffle_income"), Sum("all_raffle_cost")
            )
            self.set_user_finance(user_id, res)
            self.conn.set(f"wxs:user:raffle:{user_id}", 1, 60 * 60 * 48)

            if res.get("all_raffle_income__sum", 0) < res.get(
                "all_raffle_cost__sum", 0
            ):
                self.set_user_bit(user_id, 1)
            else:
                self.set_user_bit(user_id, 0)

        if r_f_state:
            before_income, before_cost = r_finance_res.get(
                "all_raffle_income__sum", 0
            ), r_finance_res.get("all_raffle_cost__sum", 0)
            res = Finance.objects.filter(user_uuid=user_uuid).aggregate(
                Sum("all_raffle_income"), Sum("all_raffle_cost")
            )
            now_income, now_cost = res.get("all_raffle_income__sum", 0), res.get(
                "all_raffle_cost__sum", 0
            )
            current_income, current_cost = (
                now_income - before_income,
                now_cost - before_cost,
            )

            if user_raffle_index is None:
                # 根据金额判断用户是否进行大变小逻辑
                if current_cost > current_income:
                    self.set_user_bit(user_id, 1)
                else:
                    self.set_user_bit(user_id, 0)
            else:
                if before_income < before_cost:
                    if (before_income - before_cost) * 1.3 < (
                        current_income - current_cost
                    ):
                        self.set_user_bit(user_id, 0)
                        self.set_user_finance(user_id, res)

        result = self.get_user_bit(user_id) == 1

        for c in range(raffle_count):
            good_init = self.get_good(game_uuid)

            if result:
                if self.check_good_level(game_uuid, good_init):
                    good_init = self.good_max_to_mix_v2(game_uuid, good_init)
            raffle_good_list.append(good_init)
            # 放入抽奖结果队列
            if raffle_good.get(good_init, 0) > 0:
                raffle_good[good_init] += 1
            else:
                raffle_good[good_init] = 1
        return raffle_good, raffle_good_list


def get_min_good(game_uuid, raffle_count):
    good_uuid_list = []
    game = WuxianshangGame.objects.filter(uuid=game_uuid).first()

    good_level_dict = {}
    good_level_list = GoodLevel.objects.filter(
        game_type=GoodLevelGameType.wuxianshang.value
    ).filter(deleted=False)
    for v in good_level_list:
        if v.title == "白银款" or v.title == "黄金款":
            good_level_dict[str(v.uuid)] = 1

    goods = WuxianshangGameGood.objects.filter(game_uuid=game_uuid)

    for g in goods:
        if good_level_dict.get(str(g.level_uuid), 0):
            juqi_good = JuqiGood.objects.filter(uuid=g.good_uuid).first()
            if juqi_good.recovery_price <= game.price:
                good_uuid_list.append(str(g.good_uuid))

    raffle_good_list = []
    for _ in range(raffle_count):
        raffle_good_list.append(choice(good_uuid_list))

    raffle_good_dict = {}
    for v in raffle_good_list:
        if raffle_good_dict.get(v, 0) > 0:
            raffle_good_dict[v] += 1
        else:
            raffle_good_dict[v] = 1

    return raffle_good_dict


def check_user_id_is_t(user_id):
    user_ids = get_web_settings_statistical_exclude_user_uid_list()
    if user_ids.count(user_id) > 0:
        return True
    return False


def gen_random_raffle_list(good_weight):
    all_good_weight = 0
    for k, v in good_weight.items():
        all_good_weight += v

    all_good_num = int(all_good_weight * 10)

    goods = [0] * all_good_num
    index = range(all_good_num)
    for k, v in good_weight.items():
        for i in range(int(v * 10)):
            good_index = choice(index)
            if goods[good_index] == 0:
                goods[good_index] = k
            else:
                while True:
                    good_index = choice(index)
                    if goods[good_index] == 0:
                        goods[good_index] = k
                        break
    return goods, all_good_num


def get_wxs_game_goods(game_uuid, exclude: list, result):
    cs_good_level = GoodLevel.objects.filter(
        game_type=GoodLevelGameType.wuxianshang.value, title="传说款", deleted=False
    ).first()
    goods = (
        WuxianshangGameGood.objects.filter(game_uuid=game_uuid)
        .filter(deleted=False)
        .filter(good_type=0)
        .order_by("-sort")
        .order_by("-id")
    )
    goods_weight = []
    for g in goods:
        if str(g.level_uuid) in exclude:
            continue
        if result and g.level_uuid == cs_good_level.uuid:
            goods_weight.append((str(g.good_uuid), float(g.good_weight)))
            continue
        goods_weight.append((str(g.good_uuid), float(g.good_weight)))
    return goods_weight


def random_raffle_goods(raffle_count: int, goods_weight: list):
    raffle_goods_list = []
    raffle_goods_dict = {}
    goods_list = [item[0] for item in goods_weight]
    goods_weight_list = [item[1] for item in goods_weight]

    for _ in range(raffle_count):
        goods_uuid = random.choices(goods_list, goods_weight_list)[0]
        raffle_goods_list.append(goods_uuid)

        if raffle_goods_dict.get(goods_uuid, 0) == 0:
            raffle_goods_dict[goods_uuid] = 1
        else:
            raffle_goods_dict[goods_uuid] += 1

    return raffle_goods_dict, raffle_goods_list


"""

# 从redis.list中pop一个赏品
def get_good(conn, game_uuid):
    return conn.lpop(game_uuid)


# 维护wxs出奖结果队列
def raffle_record(conn, game_uuid, good_uuid):
    conn.lpush(f"wxs:{game_uuid}:raffle_record", good_uuid)


# 校验商品的等级是否需要进行大变小
def check_good_level(conn, game_uuid, good_uuid):
    good_uuids = list(conn.get(f"wxs:{game_uuid}:max:to:min:good_uuids", []))
    try:
        good_uuids.index(good_uuid)
        return True
    except IndexError:
        return False


# 实现同级别商品大变小
def good_max_to_mix(conn, game_uuid, good_uuid, old_good):
    good = WuxianshangGameGood.objects.filter(game_uuid=game_uuid, good_uuid=good_uuid)

    good_uuids = list(conn.get(f"wxs:{game_uuid}:max:to:min:good_uuids", []))
    good_level_ = list(conn.get(f"wxs:{game_uuid}:{good.level_uuid}", []))

    for v in good_uuids:
        if v == good_uuid:
            if good_level_.index(good_uuid) > 3:
                return good_uuid
            else:
                choice_good_level_ = good_level_[4:]
                while True:
                    new_good_ = choice(choice_good_level_)

                    result = conn.linsert(
                        game_uuid, "before", new_good_, old_good
                    )  # 在队列中的第一个新赏品前插入旧的赏品
                    if result != -1:
                        break

                    choice_good_level_.remove(new_good_)

                conn.lrem(game_uuid, new_good_, 1)  # 删除队列中第一个新赏品

                return new_good_


def qjs_raffle(conn, user_id, game_uuid, raffle_count):
    raffle_good = {}

    # 从redis.bitmap中根据user_id取标志位；1:需要盈利控制,0:不需要
    result = conn.getbit("users", user_id)

    for c in range(raffle_count):
        good_init = ""

        # 盈利(盈利大于130%)用户抽奖逻辑
        if result:
            # 第一次抽奖
            good_init = get_good(conn, game_uuid)
            # 校验赏品是否需要进行大变小逻辑
            if check_good_level(conn, game_uuid, good_init):
                new_good_init = good_max_to_mix(conn, game_uuid, good_init, good_init)
                good_init = new_good_init
        # 正常用户抽奖逻辑
        else:
            good_init = get_good(conn, game_uuid)
        # 放入抽奖结果队列
        if raffle_good[good_init] > 0:
            raffle_good[good_init] += 1
        else:
            raffle_good[good_init] = 1

    # TODO 根据盈利用户 本次抽奖记录+以往亏损记录 重新统计 满足条件后回归正常模式
    # if result:
    #     finance = Finance.objects.filter(user_uuid=user_id)
    #     # if finance.all_raffle_profit <
    return raffle_good

    # 取用户在所有无限赏池子的抽奖次数
        game_raffle_count = conn.get(f"wxs:{user_id}:count", 0)
    else:
    conn.incr(f"wxs:{user_id}:count")
                profit_user_count = conn.get("wxs:profit_user:count", 1000)  # 盈利用户抽奖 奶 次数
    normal_user_count = conn.get("wxs:normal_user:count", 200)   # 正常用户抽奖 毒奶 次数

            # 奖品价值大于80
            # if get_good_level(conn, good_init) > 4:
            
                 # 盈利用户抽奖达到 奶次数后 从大奖队列中取
            # if game_raffle_count >= profit_user_count:
            #     if conn.llen(f"wxs:{game_uuid}:surplus_goods") > 0:
            #         good = int(conn.lpop(game_uuid+"raffle"))
            #         conn.set(f"wxs:{user_id}:count", 0)
            #         continue
        
                if get_good_level(conn, good) > 4:
                    # 将当前元素重新放入到 大奖池 中
                    conn.rpush(f"wxs:{game_uuid}:surplus_goods", good)

                    good = get_min_good()
                    conn.lrem(game_uuid, good, 1)
            else:
                conn.incr(f"wxs:{user_id}:count")
                good = get_raffle(conn, game_uuid)

"""
